package com.pusilkom.uploader;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;

import com.pusilkom.logger.Debuger;
import com.pusilkom.logger.FileLoger;

public class ListenerAutodebetWorkerThread implements Runnable{
	
	private BufferedReader bufferedReader;
	private Socket client;
	private AutodebetWorkerConfig conf;
	private String strCmd;
	private FileLoger flog;
	private Debuger agent;
	private Socket uploadClient;
	
	public ListenerAutodebetWorkerThread(Socket con, AutodebetWorkerConfig config, FileLoger log) {
		this.client = con;
		this.conf = config;
		this.flog = log;
		this.agent = new Debuger(this.conf);
	}
	
	/**
	 * Run the autodebet worker thread
	 */
	@Override
	public void run() {
		try {
			agent.debug("Reading data from socket stream");
			bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));			
			strCmd = bufferedReader.readLine();	
			processCmd();
		} catch (IOException e) {
			flog.writeException(e, "Error IO buffered reader");
		}	
	}
	
	/**
	 * Read string command from stream
	 * @return String[] command
	 * 0 - Command [UPL-> upload , DON -> Download]
	 * 1 - Nama file
	 * 2 - Lokasi / path file
	 * 3 - Terminal ID
	 * 4 - Merchant ID
	 * 5 - Institution ID
	 * 6 - File ID
	 */
	private String[] readStrCmd() {
		agent.debug("Reading and parsing received message "+strCmd);
		StringTokenizer st = new StringTokenizer(strCmd,"|");
		String[] cmd = new String[st.countTokens()];
		for(int i=0; st.hasMoreTokens(); i++) {
			cmd[i] = st.nextToken();
		}
		return cmd;
	}
	
	/**
	 * Processing command 
	 */
	private void processCmd() {
		String[] cmd = this.readStrCmd();
		//upload file, 
		if(cmd[0].equalsIgnoreCase("UPL")) {
			agent.debug("Starting upload file");
			uploadAutodebetFile(cmd);
		}
		//download file
		else if(cmd[0].equalsIgnoreCase("DON")) {
			agent.debug("Starting download file");
			downloadAutodebetFile(cmd);
		}
	}
	
	/**
	 * Uploading file
	 * @param String msg : param for uploading file
	 */
	private void uploadAutodebetFile(String[] msg) {
		OutputStream oos = null;		
		if(!openConnectionToFEP()) return;
		try {
			oos = uploadClient.getOutputStream();
		} catch (IOException e1) {
			flog.writeException(e1, "I/O Error while getting output stream from socket for upload");
		} catch (NullPointerException e2) {
			flog.writeException(e2, "Trying to get null socket from uploadClient");
		}
		String filePath = msg[2];
		String cmd = this.getTransactionType(msg[1]);
		if(filePath.endsWith(".zip") || filePath.endsWith(".ZIP")) {
			agent.debug("Upload zip file begin . . .");
			try {
				StringTokenizer st = new StringTokenizer(".",msg[1]);
				String fileName = st.nextToken()+".TRX";
				//send header first
				String header = cmd+"|"+fileName+"|"+msg[3]+"|"+msg[4]+"|"+msg[5]+"|"+msg[6]+'\n';
				//oos.writeObject(header);
				oos.flush();
				ZipFileReader zip = new ZipFileReader(filePath);				
				ZipEntry ze = zip.getZipEntry(fileName);
				if(ze.getSize() > 0) {
					BufferedReader buffRead = new BufferedReader(new InputStreamReader(zip.zf.getInputStream(ze)));
					String line;
					while((line = buffRead.readLine()) != null) {
						//oos.writeObject(line+'\n');
						oos.flush();
					}
				}
			} catch (FileNotFoundException e) {
				flog.writeException(e, "File nout found error");
			} catch (IOException e) {
				flog.writeException(e, "I/O Error while reading entry of zip file");
			} catch (NullPointerException e2) {
				flog.writeException(e2, "Trying to get null socket from uploadClient");
			}
			agent.debug("Upload zip file finished");
		}
		else if(filePath.endsWith(".trx") || filePath.endsWith(".TRX")) {
			agent.debug("Upload TRX file begin . . .");
			try {
				//send header first
				String header = cmd+"|"+msg[1]+"|"+msg[3]+"|"+msg[4]+"|"+msg[5]+"|"+msg[6]+'\n';				
				byte[] hdr = header.getBytes();
				oos.write(hdr);
				oos.flush();				
				
				//send the file
				byte[] buff = new byte[1024];
				TextFileReader txt = new TextFileReader(filePath);							
				while(txt.fis.read(buff) != -1) {
					oos.write(buff);
					oos.flush();
				}
				
				
			} catch (FileNotFoundException e) {
				flog.writeException(e, "File nout found error");
				closeConnectionToFEP();
			} catch (IOException e) {
				flog.writeException(e, "I/O Error while reading text file");
				closeConnectionToFEP();
			} catch (NullPointerException e2) {
				flog.writeException(e2, "Trying to get null socket from uploadClient");
			}
			agent.debug("Upload TRX file finished");
		}
		closeConnectionToFEP();
	}
	
	private void downloadAutodebetFile(String[] msg) {
		
	}
	
	private String getTransactionType(String fileName) {
		agent.debug("fileName: "+fileName);
		StringTokenizer st = new StringTokenizer(fileName,"-");
		String cmd = st.nextToken();
		agent.debug("Command: "+cmd);
		return cmd;
	}
	
	private boolean openConnectionToFEP() {
		try {
			uploadClient = new Socket(conf.getParameter("server_upload"),Integer.parseInt(conf.getParameter("port_upload")));
			return true;
		} catch (NumberFormatException e) {
			flog.writeException(e, "Upload port number must be number");	
			return false;
		} catch (UnknownHostException e) {
			flog.writeException(e, "Unknown host for server_upload, check config file");
			return false;
		} catch (IOException e) {
			flog.writeException(e, "I/O Error while creating socket for upload");
			return false;
		}
	}
	
	private void closeConnectionToFEP() {
		try {
			uploadClient.close();
		} catch (IOException e) {
			flog.writeException(e, "I/O Error while closing socket for upload");
		}
	}
}
